/*
 * Copyright 2010-2020 Alfresco Software, Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.activiti.engine.impl.cmd;

import java.io.Serializable;
import java.util.Map;

import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.debug.Contants;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityImpl;

/**
 */
public class ExecuteAsyncExecutionJobCmd implements Command<Object>, Serializable {

	private static final long serialVersionUID = 1L;
	protected ExecutionEntity execution;
	private boolean notDelParent;
	private Map<String, Object> cacheAttr;

	public ExecuteAsyncExecutionJobCmd(ExecutionEntity execution, boolean notDelParent, Map<String, Object> cacheAttr) {
		this.execution = execution;
		this.notDelParent = notDelParent;
		this.cacheAttr = cacheAttr;
	}

	@Override
	public Object execute(CommandContext commandContext) {
		commandContext.addAttributes(cacheAttr);
		if(notDelParent) {
			// 是否需要在end时删除parent execution
			commandContext.addAttribute(Contants.NOT_DELETE_PARENT, notDelParent);
		}
		FlowElement currentFlowElement = execution.getCurrentFlowElement();
		if (currentFlowElement instanceof FlowNode) {
			// 把execution强制放入缓存，不然无法更新execution
			forceToInsert(commandContext, (ExecutionEntityImpl)execution);
			Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution, true);
        } else if (currentFlowElement instanceof SequenceFlow) {
        	// 把execution强制放入缓存，不然无法更新execution
        	forceToCache(commandContext, (ExecutionEntityImpl)execution);
            // 强制走同步的ContinueProcess，因为在并行网关已经进行了异步
            Context.getAgenda().planContinueProcessSynchronousOperation(execution);
        }

		if (commandContext.getEventDispatcher().isEnabled()) {
			commandContext.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.JOB_EXECUTION_SUCCESS, execution));
		}

		return null;
	}

	private void forceToCache(CommandContext commandContext, ExecutionEntityImpl execution) {
		commandContext.getExecutionEntityManager().update(execution);
	}

	private void forceToInsert(CommandContext commandContext, ExecutionEntityImpl execution) {
		commandContext.getExecutionEntityManager().insert(execution);
	}

}
